local function GetStringsTable()
    return TUNING.NPC_CHAT_TABLE[ type(TUNING.__NPC_LANGUAGE)=="function" and TUNING.__NPC_LANGUAGE() or TUNING.__NPC_LANGUAGE ] ["npc_item_magic_tophat"] or {}
end

-- STRINGS.CHARACTERS.GENERIC.ACTIONFAIL.SIGN_FOR_SALE = GetStringsTable().action_str_table

local NPC_MAGIC_ITEM_USE = Action({priority = 70})
NPC_MAGIC_ITEM_USE.id = "NPC_MAGIC_ITEM_USE"
NPC_MAGIC_ITEM_USE.str = GetStringsTable().action_str
NPC_MAGIC_ITEM_USE.fn = function(act)	-------- sg.GoToState 执行完后才会执行这里
	-- local target = act.target	
	local invobject = act.invobject
	local doer = act.doer

	if doer and doer:HasTag("player") then
		local hat = doer.components.inventory:GetEquippedItem(EQUIPSLOTS.HEAD)
		if hat == invobject then
			return true
		end
	end
	return false
end
AddAction(NPC_MAGIC_ITEM_USE) 

-- AddComponentAction("INVENTORY", "writeable", function(inst, doer, actions)
-- AddComponentAction("SCENE", "cage", function(inst, doer, actions)
-- AddComponentAction("SCENE", "followerstay", function(inst, doer, actions, rightclick)
-- AddComponentAction("USEITEM", "sharpness" , function(inst, doer, target, actions)
-- AddComponentAction("POINT", "sea2land", function(inst, doer, pos, actions, right)
-- AddComponentAction("EQUIPPED", "complexprojectile", function(inst, doer, target, actions, right)

AddComponentAction("INVENTORY", "npc_components_magic_item" ,function(inst,doer,actions)
	if inst and inst.prefab == "npc_item_magic_tophat" then
		table.insert(actions, ACTIONS.NPC_MAGIC_ITEM_USE)
	end
end)
AddStategraphActionHandler("wilson",ActionHandler(ACTIONS.NPC_MAGIC_ITEM_USE, "start_using_tophat_npc_item"))
AddStategraphActionHandler("wilson_client",ActionHandler(ACTIONS.NPC_MAGIC_ITEM_USE, "start_using_tophat_npc_item"))

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------- 服务器用的SG
local function Sever_on_equip_hat(inst)
	local hat = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HEAD)
	if hat and hat.components.equippable and hat.components.equippable.onequipfn  then
		hat.components.equippable.onequipfn(hat,inst)
		inst:PushEvent("equip", { item = hat, eslot = EQUIPSLOTS.HEAD})
	end
end
local function Sever_on_unequip_hat(inst)
	local hat = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HEAD)
	if hat and hat.components.equippable and hat.components.equippable.onunequipfn  then
		hat.components.equippable.onunequipfn(hat,inst)
	end
end
local function OpenContainer_Server(inst)
	local hat = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HEAD)
	if hat and hat.components.container and hat.components.container:IsOpenedBy(inst) ~= true  then
		hat.components.container:Open(inst)
		-- print("++++++++++++++ container event open")
	end
end
local function CloseContainer_Server(inst)
	local hat = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HEAD)			 
	if hat and hat.components.container and hat.components.container:IsOpenedBy(inst) == true  then
		hat.components.container:Close()
		-- print("++++++++++++++ container event close")
	end
end
AddStategraphState("wilson",State{		-------------- start_using_tophat_npc_item
	------------------------------------------------------------------
	name = "start_using_tophat_npc_item",
	tags = { "doing", "busy" },

	onenter = function(inst)
		inst.components.locomotor:Stop()

		local buffaction = inst:GetBufferedAction()
		local hat = buffaction ~= nil and buffaction.invobject or nil
		inst.AnimState:PlayAnimation(
			hat ~= nil and
			inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HEAD) == hat and
			"tophat_equipped_pre" or
			"tophat_empty_pre"
		)
		-- inst.components.inventory:ReturnActiveActionItem(hat)
	end,
	events =
	{
		EventHandler("animover", function(inst)
			if inst.AnimState:AnimDone() then
				inst.sg:GoToState("using_tophat_npc_item")
			end
		end),
	},	
	------------------------------------------------------------------
})
AddStategraphState("wilson",State{		-------------- using_tophat_npc_item
	------------------------------------------------------------------
	name = "using_tophat_npc_item",
	tags = { "doing", "overridelocomote"}, -- "overridelocomote"

	onenter = function(inst)
		if inst:PerformBufferedAction() then
			local hat, equipped, build, skin_build

			Sever_on_unequip_hat(inst)				
			hat = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HEAD)
			inst:DoTaskInTime(0.5,function()
				OpenContainer_Server(inst)
			end)

			if hat then
				equipped = true
				build = hat.AnimState:GetBuild()
				skin_build = hat:GetSkinBuild()
			end

			inst.AnimState:PlayAnimation(equipped and "tophat_equipped_start" or "tophat_empty_start")
			inst.AnimState:PushAnimation("tophat_loop")
			if skin_build ~= nil then
				inst.AnimState:OverrideItemSkinSymbol("swap_hattop", skin_build, "swap_hat", hat.GUID, build)
			else
				inst.AnimState:OverrideSymbol("swap_hattop", build, "swap_hat")
			end

			--shadow particles
			inst.AnimState:OverrideSymbol("tophat_fx_float", "tophat_fx", "fx_float")
			inst.AnimState:SetSymbolMultColour("tophat_fx_float", 1, 1, 1, .5)
			inst.sg.statemem.fx_float = SpawnPrefab("tophat_using_shadow_fx")
			inst.sg.statemem.fx_float:AttachToTopHatUser(inst)

			--shadow swirl
			inst.sg.statemem.fx_front = SpawnPrefab("tophat_swirl_fx")
			inst.sg.statemem.fx_front:AttachToTopHatUser(inst, true)
			inst.sg.statemem.fx_back = SpawnPrefab("tophat_swirl_fx")
			inst.sg.statemem.fx_back:AttachToTopHatUser(inst, false)
		else
			inst.AnimState:PlayAnimation(
				inst.AnimState:IsCurrentAnimation("tophat_equipped_pre") and
				"tophat_equipped_pst" or
				"tophat_empty_pst"
			)
			inst.AnimState:SetTime(9 * FRAMES)
			inst.sg:RemoveStateTag("overridelocomote")
		end
		
		-- print("+++++++++++++++++++ using_tophat_npc_item server")

	end,

	events =
	{
		-- EventHandler("ontalk", OnTalk_Override),
		-- EventHandler("donetalking", OnDoneTalking_Override),
		EventHandler("equip", function(inst)
			if inst.AnimState:IsCurrentAnimation("tophat_loop") then
				inst.AnimState:PlayAnimation("tophat_item_in")
				inst.AnimState:PushAnimation("tophat_loop")
			end
		end),
		EventHandler("unequip", function(inst)
			if inst.AnimState:IsCurrentAnimation("tophat_loop") then
				inst.AnimState:PlayAnimation("tophat_item_in")
				inst.AnimState:PushAnimation("tophat_loop")
			end
			CloseContainer_Server(inst)
		end),

		EventHandler("locomote", function(inst)
			-- print("info : ++++++++++ locomote in server") --------- 只有server 才会触发这个event

			if inst.sg:HasStateTag("overridelocomote") then
				local data = { locomoting = true, talktask = inst.sg.statemem.talktask }
				inst.sg.statemem.talktask = nil
				inst.sg.statemem.stopusingmagiciantool = true
				inst.sg:GoToState("stop_using_tophat_npc_item", data)
				CloseContainer_Server(inst)
				SendModRPCToClient(CLIENT_MOD_RPC["NPC_MOD_ACTION"]["MAGIC_ITEM_STOP_USE"],inst,inst)
				inst.components.locomotor:Stop()

				return true
			end
		end),
		EventHandler("animqueueover", function(inst)
			if inst.AnimState:AnimDone() then
				inst.sg:GoToState("idle")
			end
		end),
	},

	-- onupdate = function(inst)
	-- 	if inst.sg:HasStateTag("overridelocomote") and inst.components.playercontroller then
	-- 		local hat = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HEAD)
	-- 		if hat ~= inst.sg.statemem.hat then
	-- 			print("hat error")
	-- 			inst.sg:GoToState("idle")
	-- 		end
	-- 	end
	-- end,

	onexit = function(inst)
		if not inst.sg.statemem.stopusingmagiciantool then
			--interrupted
			inst.AnimState:ClearOverrideSymbol("swap_hattop")
			inst.AnimState:ClearOverrideSymbol("tophat_fx_float")
			inst.AnimState:SetSymbolMultColour("tophat_fx_float", 1, 1, 1, 1)
			if inst.components.magician ~= nil then
				if not inst.sg.statemem.is_going_to_action_state then
					inst.components.magician:DropToolOnStop()
				end
				inst.components.magician:StopUsing()
			end
		end
		if inst.sg.statemem.fx_float ~= nil then
			inst.sg.statemem.fx_float:Remove()
			inst.sg.statemem.fx_front:Remove()
			inst.sg.statemem.fx_back:Remove()
		end
		-- CancelTalk_Override(inst)
	end,
	------------------------------------------------------------------
})

AddStategraphState("wilson",State{		-------------- stop_using_tophat_npc_item
	name = "stop_using_tophat_npc_item",
	tags = { "idle", "overridelocomote" ,"busy"},

	onenter = function(inst, data)
		-- 'locomoting' means we got here via locomotion control rather than ACTIONS.STOPUSINGMAGICTOOL:
		-- - We must manually stop magician
		-- - Any buffered actions would be our NEXT action after we play some pst anim
		local locomoting
		if data ~= nil then
			locomoting = data.locomoting
			inst.sg.statemem.talktask = data.talktask
		end

		local held, equipped
		local hat = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HEAD)
		if hat then
			equipped = true
		end

		if not locomoting then
			if not inst:PerformBufferedAction() then
				inst.sg:GoToState("idle")
				Sever_on_equip_hat(inst)
				return
			end
		end

		if equipped then
			--NOTE: anim is duplicated for both swap_hat and swap_hattop
			--      so that it'll be seamless for clients predicting the
			--      anim before the re-equip happens on the server.
			inst.AnimState:PlayAnimation("tophat_equipped_pst")
			inst.AnimState:ClearOverrideSymbol("swap_hattop")
		elseif held then
			inst.AnimState:PlayAnimation("tophat_empty_pst")
		else
			--dropped on ground
			inst.sg:GoToState("idle")
			Sever_on_equip_hat(inst)
		end
	end,

	timeline =
	{
		TimeEvent(7 * FRAMES, function(inst)
			inst.sg:AddStateTag("canrotate")
		end),
		TimeEvent(8 * FRAMES, function(inst)
			inst.sg:RemoveStateTag("overridelocomote")
		end),
	},

	events =
	{
		EventHandler("ontalk", function(inst)
			if inst.sg:HasStateTag("overridelocomote") then
				-- OnTalk_Override(inst)
				return true
			end
			-- CancelTalk_Override(inst, true)
		end),
		-- EventHandler("donetalking", OnDoneTalking_Override),
		EventHandler("equip", function(inst, data)
			--suppress equip events for re-equipping our magiciantool hat
			return data ~= nil and data.item == inst.sg.statemem.hat
		end),
		EventHandler("locomote", function(inst)
			--don't handle locomotion states yet
			--we still allows buffering them, since we are not "busy"
			Sever_on_equip_hat(inst)
			return inst.sg:HasStateTag("overridelocomote")
		end),
		EventHandler("animover", function(inst)
			if inst.AnimState:AnimDone() then
				inst.sg:GoToState("idle")
				Sever_on_equip_hat(inst)
			end
		end),
	},

	onexit = function(inst)
		inst.AnimState:ClearOverrideSymbol("swap_hattop")
		inst.AnimState:ClearOverrideSymbol("tophat_fx_float")
		inst.AnimState:SetSymbolMultColour("tophat_fx_float", 1, 1, 1, 1)
		-- CancelTalk_Override(inst)
		Sever_on_equip_hat(inst)
	end,
})
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------- 客户端用的SG --- 有个event没法在客户端触发，必须用RPC中转
AddStategraphState("wilson_client",State{	------------- start_using_tophat_npc_item
	name = "start_using_tophat_npc_item",
	tags = { "doing", "busy" },

	onenter = function(inst)
		inst.components.locomotor:Stop()

		local buffaction = inst:GetBufferedAction()
		-- local hat = buffaction ~= nil and buffaction.invobject or nil
		-- inst:AddTag("usingmagiciantool")
		local hat = inst.replica.inventory:GetEquippedItem(EQUIPSLOTS.HEAD)
		if hat ~= nil and inst.replica.inventory:GetEquippedItem(EQUIPSLOTS.HEAD) == hat then
			inst.AnimState:PlayAnimation("tophat_equipped_pre")
			inst.AnimState:PushAnimation("tophat_equipped_lag", false)
			inst.sg.statemem.equipped = true
		else
			inst.AnimState:PlayAnimation("tophat_empty_pre")
			inst.AnimState:PushAnimation("tophat_empty_lag", false)
		end

		if buffaction ~= nil then
			inst:PerformPreviewBufferedAction()
		end
		inst.sg:SetTimeout(TIMEOUT)
	end,

	timeline =
	{
		TimeEvent(8 * FRAMES, function(inst)
			inst.sg:RemoveStateTag("busy")
		end),
	},

	onupdate = function(inst)
		if inst:HasTag("doing") then
			if inst.entity:FlattenMovementPrediction() then
				inst.sg:GoToState("using_tophat_npc_item")
			end
		elseif inst.bufferedaction == nil then
			inst.AnimState:PlayAnimation(inst.sg.statemem.equipped and "tophat_equipped_pst" or "tophat_empty_pst")
			inst.AnimState:SetTime(9 * FRAMES)
			inst.sg:GoToState("idle", true)
		end
	end,

	ontimeout = function(inst)
		inst:ClearBufferedAction()
		inst.AnimState:PlayAnimation(inst.sg.statemem.equipped and "tophat_equipped_pst" or "tophat_empty_pst")
		inst.AnimState:SetTime(9 * FRAMES)
		inst.sg:GoToState("idle", true)
	end,
})

AddStategraphState("wilson_client",State{	------------- using_tophat_npc_item
	name = "using_tophat_npc_item",
	tags = { "doing","overridelocomote","using_tophat_npc_item"},

	onenter = function(inst)
		inst.entity:SetIsPredictingMovement(false)
		inst.sg:SetTimeout(TIMEOUT)
		-- print("+++++++++++++++++++ using_tophat_npc_item client")
	end,

	onupdate = function(inst)
		if inst.bufferedaction == nil and not inst:HasTag("usingmagiciantool") then
			inst.sg:GoToState("idle", "noanim")
		end
	end,

	ontimeout = function(inst)
		if inst.bufferedaction ~= nil and inst.bufferedaction.ispreviewing then
			inst:ClearBufferedAction()
			inst.sg:GoToState("idle")
		end
	end,

	events =
	{
		-- EventHandler("locomote", function(inst)	---------- 这个evenet 不会在客户端触发
		-- 	print("info locomote event : using_tophat_npc_item  clicent")
		-- 	inst.sg:GoToState("stop_using_tophat_npc_item", true)
		-- 	return true
		-- end),
	},

	onexit = function(inst)
		-- inst.entity:SetIsPredictingMovement(true)
	end,
})

AddStategraphState("wilson_client",State{	------------- stop_using_tophat_npc_item
	name = "stop_using_tophat_npc_item",
	tags = { "idle", "overridelocomote" },

	onenter = function(inst, locomoting)

		inst.AnimState:PlayAnimation("tophat_equipped_pst")
		inst.components.locomotor:Stop()
		inst.entity:SetIsPredictingMovement(false)
		inst.sg:SetTimeout(TIMEOUT)
		-- print("+++++++++++++++++++ stop_using_tophat_npc_item",locomoting)
		if locomoting then
			inst.sg.statemem.overridelocomote = true
			inst.components.playercontroller:RemotePredictOverrideLocomote()
		else
			inst:PerformPreviewBufferedAction()
		end
	end,

	onupdate = function(inst)
		if inst.sg:HasStateTag("overridelocomote") then
			if inst.sg.statemem.overridelocomote then
				inst.components.playercontroller:RemotePredictOverrideLocomote()
			end
		elseif not inst.components.locomotor:HasDestination() then
			inst.sg:GoToState("idle", "noanim")
			return
		end
		if inst.sg.statemem.stopped then
			if not (inst.AnimState:IsCurrentAnimation("tophat_equipped_pst") or
					inst.AnimState:IsCurrentAnimation("tophat_empty_pst")) then
				inst.sg:GoToState("idle", "noanim")
				return
			end
		elseif not inst:HasTag("usingmagiciantool") then
			inst.sg.statemem.stopped = true
			inst.entity:SetIsPredictingMovement(false)
		end
	end,

	timeline =
	{
		TimeEvent(7 * FRAMES, function(inst)
			inst.sg:AddStateTag("canrotate")
		end),
		TimeEvent(8 * FRAMES, function(inst)
			inst.sg:RemoveStateTag("overridelocomote")
		end),
	},

	events =
	{
		EventHandler("locomote", function(inst)
			return inst.sg:HasStateTag("overridelocomote")
		end),
	},

	onexit = function(inst)
		inst.entity:SetIsPredictingMovement(true)
	end,
})


AddClientModRPCHandler("NPC_MOD_ACTION","MAGIC_ITEM_STOP_USE",function(inst)
	if TheNet:GetIsMasterSimulation() ~= true and inst and inst.userid  then	------ 只在客户端执行
		if inst.sg and inst.sg.GoToState then	------- 关了延迟补偿会导致  inst.sg 为nil
			inst.sg:GoToState("stop_using_tophat_npc_item",true)
		end
	end
end)